
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <asm/io.h>


static int major;
static struct class *led_class;
/* 操作寄存器 */
static volatile unsigned int * IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;
/* GPIO5_GDIR 地址：0x020AC004 */
static volatile unsigned int * GPIO5_GDIR;
/* GPIO5_DR 地址：0x020AC000 */
static volatile unsigned int * GPIO5_DR;


static int led_open(struct inode *inode, struct file *filp)
{
	
	/* 使能GPIO5模块,IMX660LL默认开启GPIO5 */
	/* 配置引脚为GPIO功能,GPIO5_3。方法先清零再置1 */
	*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 &= ~0xf;
	*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 |= 0x5;
	/* 设置GPIO方向,输出方向,配置GPIO为Output*/
	*GPIO5_GDIR |= (1<<3);
	return 0;
}


static ssize_t led_write(struct file *filp, const char __user *buf,
			 size_t count, loff_t *ppos)
{
	int k;
	/* 得到数据 */
	char val;
	k = copy_from_user(&val, buf, 1);
	/* 设置数据，高电平还是低电平 */
	if(val)
	{
		/* 亮灯 */
		*GPIO5_DR &= ~(1<<3); 
	}
	else
	{
		/* 灭灯 */
		*GPIO5_DR |= (1<<3);
	}
	return 1;
}

static struct file_operations led_fops = {
	.owner		= THIS_MODULE,
	.write		= led_write,
	.open		= led_open,
};

/* 入口函数 */
static int __init led_init(void)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	//注册结构体
	major = register_chrdev(0, "100ask_led", &led_fops);
	/* 地址映射
	 * IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3的寄存器地址为：0x0229000+0x14
	 * ioremap操作时，是按照一页的大小去映射的，即写入是4，但实际映射了4k
	 */
	IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(0x02290000+0x14, 4);
	GPIO5_GDIR = ioremap(0x020AC004, 4);
	GPIO5_DR = ioremap(0x020AC000, 4);
	
	led_class = class_create(THIS_MODULE, "myled");
	/* 创建驱动节点 */
	device_create(led_class, NULL, MKDEV(major, 0), NULL, "myled");/* /dev/myled */
	return 0;
}

static void __exit led_exit(void)
{
	iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3);
	iounmap(GPIO5_GDIR);
	iounmap(GPIO5_DR);

	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	/* 销毁设备号 */
	device_destroy(led_class, MKDEV(major, 0));
	/* 销毁类 */
	class_destroy(led_class);
	unregister_chrdev(major, "100ask_led");
}



/* 使用宏修饰函数，导出作为指令 */
module_init(led_init);
module_exit(led_exit);
/* 必须包含下面这句，才能起作用 */
MODULE_LICENSE("GPL");

